package com.example.jetpackdemo.basic_camera;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.Build;
import android.preference.PreferenceManager;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.util.Pair;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * @author: tuyrt7 on 2020/12/2.
 */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";

    private SurfaceHolder mHolder;
    private CameraConfig mConfig;

    private Camera mCamera;
    private Camera.Parameters mParameters;
    private MediaRecorder mMediaRecorder;
    private boolean isRecording;
    private OnVideoSavedCallback mOnVideoSavedCallback;
    private Uri videoFileUri;

    public CameraPreview(Context context) {
        this(context, null);
    }

    public CameraPreview(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public CameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView(context);
    }

    private void initView(Context context) {
        mHolder = getHolder();
        mHolder.addCallback(this);

        mConfig = new CameraConfig();
    }

    public void setCameraConfig(CameraConfig cameraConfig) {
        mConfig = cameraConfig;
    }

    public void startCameraPreview() {
        getCameraInstance();
        mParameters = mCamera.getParameters();
//      mParameters.setJpegQuality(ImageFormat.JPEG);
        // 设置 pictureSize focus
        if (!mConfig.isHasGpsData()) {
            mParameters.removeGpsData();
        }

        mCamera.stopPreview();
        mCamera.setParameters(mParameters);
        mCamera.startPreview();
    }

    public enum CaptureMode {
        IMAGE(0),
        VIDEO(1);
        private final int mId;

        int getId() {
            return mId;
        }

        CaptureMode(int id) {
            mId = id;
        }
    }

    public void setCaptureMode(CaptureMode captureMode) {
        mConfig.setCaptureMode(captureMode);
    }

    public void takePicture(File file, OnImageSavedCallback onImageSavedCallback) {
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPictureFormat(ImageFormat.JPEG);
        parameters.setPreviewSize(640, 480);
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        mCamera.autoFocus(new Camera.AutoFocusCallback() {
            @Override
            public void onAutoFocus(boolean success, Camera camera) {
                if (success) {
                    mCamera.takePicture(null, null, new Camera.PictureCallback() {
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera) {
                            try {
                                FileOutputStream fos = new FileOutputStream(file);
                                fos.write(data);
                                fos.close();
                                onImageSavedCallback.onImageSaved(Uri.fromFile(file));
                            } catch (IOException e) {
                                onImageSavedCallback.onError(e.getMessage());
                            }
                        }
                    });
                } else {
                    onImageSavedCallback.onError("autoFocus return false.");
                }
            }
        });
    }

    public void startRecording(File file, OnVideoSavedCallback onVideoSavedCallback) {
        if (prepareVideoRecorder(file)) {
            mMediaRecorder.start();
            videoFileUri = Uri.fromFile(file);
            mOnVideoSavedCallback = onVideoSavedCallback;
            isRecording = true;
        } else {
            isRecording = false;
            releaseMediaRecorder();
            onVideoSavedCallback.onError("MediaRecorder prepared failed");
            mOnVideoSavedCallback = null;
        }
    }

    public void stopRecording() {
        if (mMediaRecorder != null) {
            mMediaRecorder.stop();
        }
        releaseMediaRecorder();

        //回调
        if (mOnVideoSavedCallback != null && isRecording) {
            mOnVideoSavedCallback.onVideoSaved(videoFileUri);
            mOnVideoSavedCallback = null;
        }
        isRecording = false;

    }


    private void releaseMediaRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();
            mMediaRecorder.release();
            mMediaRecorder = null;
            mCamera.lock();
        }
    }

    private boolean prepareVideoRecorder(File file) {
        mCamera = getCameraInstance();
        mMediaRecorder = new MediaRecorder();

        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);

        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));

        Pair<Integer, Integer> videoSize = mConfig.getVideoSize();
        mMediaRecorder.setVideoSize(videoSize.first, videoSize.second);

        mMediaRecorder.setOutputFile(file.getAbsolutePath());

        mMediaRecorder.setPreviewDisplay(mHolder.getSurface());
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
            releaseMediaRecorder();
            return false;
        }
        return true;
    }

    /**
     * 拍照回调
     */
    public interface OnImageSavedCallback {
        void onImageSaved(@NonNull Uri imageUri);

        void onError(@NonNull String exception);
    }

    /**
     * 拍照返回
     */
    public interface OnVideoSavedCallback {
        void onVideoSaved(@NonNull Uri videoUri);

        void onError(@NonNull String exception);
    }

    public Camera getCameraInstance() {
        if (mCamera == null) {
            try {
                mCamera = Camera.open();
            } catch (Exception e) {
                Log.d(TAG, "camera is not available.");
            }
        }
        return mCamera;
    }


    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        getCameraInstance();
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        mHolder.removeCallback(this);
        mCamera.setPreviewCallback(null);
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }


}
